package fun.cyhgraph.service.serviceImpl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import fun.cyhgraph.constant.MessageConstant;
import fun.cyhgraph.constant.StatusConstant;
import fun.cyhgraph.dto.DishDTO;
import fun.cyhgraph.dto.DishPageDTO;
import fun.cyhgraph.entity.Dish;
import fun.cyhgraph.entity.DishFlavor;
import fun.cyhgraph.entity.Setmeal;
import fun.cyhgraph.exception.DeleteNotAllowedException;
import fun.cyhgraph.mapper.DishFlavorMapper;
import fun.cyhgraph.mapper.DishMapper;
import fun.cyhgraph.mapper.SetmealDishMapper;
import fun.cyhgraph.mapper.SetmealMapper;
import fun.cyhgraph.result.PageResult;
import fun.cyhgraph.service.DishService;
import fun.cyhgraph.vo.DishVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 菜品管理服务实现类
 */
@Service
public class DishServiceImpl implements DishService {

    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;

    /**
     * 添加菜品和口味  （管理端）
     * @param dishDTO
     */
    public void addDishWithFlavor(DishDTO dishDTO) {
        // 不但要向dish表添加数据，还要向dish_flavor表添加口味数据
        // 1、创建一个dish对象
        Dish dish = new Dish();
        // 将dishDTO的数据复制到dish对象中
        BeanUtils.copyProperties(dishDTO, dish);
        dish.setStatus(1);   // 默认起售
        // 2、添加菜品
        dishMapper.addDish(dish);

        // 由于在动态sql中，用了useGeneralKeys=true，因此会在插入数据后自动返回该行数据的主键id，
        // 并且使用keyProperty="id"，表示将返回的主键值赋值给dish的id属性，下面就可以dish.getId()获取到id
        // 3、通过动态sql，获取刚添加的菜品的id
        Integer dishId = dish.getId();
        // 有了DTO中的flavors，加上上面的dish_id，就可以批量插入口味数据到dish_flavor表了

        // 4、先拿到口味列表：从dishDTO中获取口味list放入flavorList中
        List<DishFlavor> flavorList = dishDTO.getFlavors();
        // 判断flavorList是否为空
        if (flavorList != null && !flavorList.isEmpty()) {
            // 5、再遍历这些口味，在flavorList中批量写入菜品的dishId
            // 每条口味信息都加上了dish_id字段，这样相当于DishFlavor就有id,name,value,dish_id四个完整字段了
            flavorList.forEach(dishFlavor -> dishFlavor.setDishId(dishId));
            // 6、最后批量插入口味数据，动态sql中需要根据 , 分割，foreach批量插入
            dishFlavorMapper.insertBatch(flavorList);
        }
    }

    /**
     * 菜品条件分页查询   （管理端）
     * @param dishPageDTO
     * @return
     */
    public PageResult getPageList(DishPageDTO dishPageDTO) {
        // 1. 获取分页数据 开启分页
        PageHelper.startPage(dishPageDTO.getPage(), dishPageDTO.getPageSize());
        // 2. 查询 放入dishList
        Page<Dish> dishList = dishMapper.getPageList(dishPageDTO);
        // 3. 封装总记录数和当前页数据并返回
        return new PageResult(dishList.getTotal(), dishList.getResult());
    }

    /**
     * 根据id查询菜品和对应口味   （管理端） (用户端)
     * @param id
     * @return
     */
    public DishVO getDishWithFlavorById(Integer id) {
        // 1、根据id查询菜品数据
        Dish dish = dishMapper.getById(id);
        // 2、根据id查询对应的口味数据
        List<DishFlavor> dishFlavors = dishFlavorMapper.getByDishId(id);
        // 3、将查询到的数据封装成DishVO
        // 创建一个DishVO对象
        DishVO dishVO = new DishVO();
        // 将dish数据复制给dishVO
        BeanUtils.copyProperties(dish, dishVO);
        // 将dishFlavors数据放入dishVO
        dishVO.setFlavors(dishFlavors);
        // 返回
        return dishVO;
    }



    /**
     * 根据id修改起售停售状态   （管理端）
     * @param id
     */
    public void onOff(Integer id) {
        dishMapper.onOff(id);
    }



    /**
     * 更新菜品以及对应口味   （管理端）
     * @param dishDTO
     */
    public void updateDishWithFlavor(DishDTO dishDTO) {
        // 修改菜品表基本信息
        // 1、创建一个dish对象
        Dish dish = new Dish();    //因为dto中有口味信息，最好使用dish
        // 将dishDTO对象拷贝到dish对象中。dish中无口味信息所以接收不到口味
        BeanUtils.copyProperties(dishDTO, dish);
        // 根据id更新菜品数据
        dishMapper.update(dish);

        // 2、获取菜品id
        Integer dishId = dishDTO.getId();
        // 原来的口味和新的口味的行数据量可能不一样，不能直接更新，只能删除再批量插入
        // 3、删除原有的口味数据
        dishFlavorMapper.deleteByDishId(dishId);
        // 4、重新插入新的口味数据  与上方插入逻辑一致：从dishDTO中获取口味list放入flavorList中
        List<DishFlavor> flavorList = dishDTO.getFlavors();
        // 判断口味list是否为空
        if (flavorList != null && !flavorList.isEmpty()){
            // 5、再遍历这些口味，在flavorList中批量写入菜品的dishId
            // 每条口味信息都加上了dish_id字段，这样相当于DishFlavor就有id,name,value,dish_id四个完整字段了
            flavorList.forEach(dishFlavor -> dishFlavor.setDishId(dishId));
            // 6、最后批量插入口味数据，动态sql中需要根据 , 分割，foreach批量插入
            dishFlavorMapper.insertBatch(flavorList);
        }
    }

    /**
     * 根据ids批量删除菜品数据   （管理端）
     * @param ids
     */
    public void deleteBatch(List<Integer> ids) {
        // 1、遍历所有菜品，如果有任何一个在起售，则抛异常表示不能删除
        for (Integer id : ids){
            // 根据id查询菜品数据
            Dish dish = dishMapper.getById(id);
            // 判断菜品是否在起售
            if (dish.getStatus() == StatusConstant.ENABLE){
                throw new DeleteNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }
        // 2、遍历所有菜品，如果有关联套餐也不能删除
        // 查询当前菜品是否关联了套餐: (根据菜品id查询套餐id)
        List<Integer> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
        // 判断套餐id是否存在
        if (setmealIds != null && !setmealIds.isEmpty()){
            throw new DeleteNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
        // 3、可以批量删除菜品和对应口味数据了
        dishMapper.deleteBatch(ids);
        dishFlavorMapper.deleteBatch(ids);
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * 根据分类id查询该分类下的所有菜品  （用户端）
     * @param dish
     * @return
     */
    public List<DishVO> getDishesWithFlavorById(Dish dish) {
        // 1、根据分类id查询所有菜品数据
        List<Dish> dishList = dishMapper.getList(dish);
        // 2、创建一个DishVO列表，用于存储查询到的菜品数据
        List<DishVO> dishVOList = new ArrayList<>();
        // 3、遍历dishList 将其加上对应的口味后 封装到dishVOList
        for (Dish d : dishList){
            // 创建DishVO对象
            DishVO dishVO = new DishVO();
            // 将dishList的数据复制给dishVO
            BeanUtils.copyProperties(d, dishVO);
            // 获取菜品对应的口味数据
            List<DishFlavor> flavors = dishFlavorMapper.getByDishId(d.getId());
            // 将口味数据也放入dishVO中   现在dishVO中 既有菜品数据，也有口味数据
            dishVO.setFlavors(flavors);

            // 4、将dishVO数据封装到dishVOList中
            dishVOList.add(dishVO);
        }
        return dishVOList;
    }

}
